package cn.sc.allinpay.allfavour.base.connect.socket.connection;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

import cn.sc.allinpay.allfavour.base.connect.socket.connectfactory.ConnectParameter;

/**
 * socket通信
 * author：pany
 * on 2017/11/9 23:10
 */
public abstract class SocketConnection implements Connection {

    public static final int CONNECT_TIMEOUT = 30;//连接超时

    private Socket socket;
    protected ConnectParameter parameter;

    public SocketConnection() {
        this.parameter = getConnectParameter();
    }

    protected abstract ConnectParameter getConnectParameter();

    /**
     * 连接
     *
     * @param localAddress
     * @throws IOException
     */
    @Override
    public void connect(SocketAddress localAddress) throws IOException {
        socket = new Socket();
        //当通过Socket的输入流读数据时，如果还没有数据，就会等待。
        //Socket类的SO_TIMEOUT选项用于设定接收数据的等待超时时间，单位为毫秒，它的默认值为0，表示会无限等待，永远不会超时
        socket.setSoTimeout(parameter.getTimeout() * 1000);
        if (localAddress != null) {
            //与本地端口绑定
            socket.bind(localAddress);
        }
        //设置连接超时时间的,timeout为0表示不限超时 connect调用会一直阻塞直到连接建立或发生错误
        socket.connect(new InetSocketAddress(parameter.getIp(), parameter.getPort()), CONNECT_TIMEOUT * 1000);
    }

    /**
     * 发送
     *
     * @param data 上送数据
     * @throws IOException
     */
    @Override
    public void send(byte[] data) throws IOException {
        OutputStream out = socket.getOutputStream();
        out.write(convertSendData(data));
        out.flush();//清空缓冲区的数据流
    }

    /**
     * 装载上送报文
     * <p>
     * 报文长度(2字节) + TPDU + 报文头header
     *
     * @param data
     * @return
     */
    protected abstract byte[] convertSendData(byte[] data);


    /**
     * 接收
     *
     * @return
     * @throws IOException
     * @throws InterruptedException
     */
    @Override
    public byte[] receive() throws IOException, InterruptedException {
        InputStream is = socket.getInputStream();
        return convertReceiveData(is);
    }

    /**
     * 拆解接收报文
     *
     * @param is
     * @return
     * @throws IOException
     */
    protected abstract byte[] convertReceiveData(InputStream is) throws IOException, InterruptedException;

    @Override
    public void disconnect() throws IOException {
        if (socket != null && !socket.isClosed()) {
            socket.close();
        }
        socket = null;
    }

    protected boolean isTimeout(long beginTime, int timeout) {
        return System.currentTimeMillis() - beginTime > timeout;
    }

    protected void sleep(long sleep) throws InterruptedException {
        Thread.sleep(sleep);
    }
}
